package event.numberevent;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Vector;

import assister.ClassAssister;
import assister.MathAssister;

/**
 * 
 * @author koldar
 * @version 1.3
 *
 * @param <NUMBER>
 */
class NumberManagerExtreme<NUMBER extends Number> extends Vector<NumberListener<NUMBER>>{
	
	private static final long serialVersionUID = -8091334715902138225L;


	/*IDEA:
	 * 1) prendo il NumberListener corrente
	 * 2) considero tutte le interfacce che la sua genealogia implementa
	 * 3) considero solo le interfacce figlie di NumberListener
	 * 4) eseguo tutti i metodi che la genealogia di NumberLister implementa (guardando le apposite Annotation)
	 * 
	 */
	
	public void fireNumberEvents(NumberEvent<NUMBER> event){
		HashSet<Class<? extends NumberListener<?>>> listenerClasses=new HashSet<Class<? extends NumberListener<?>>>();
		for (NumberListener<NUMBER> numberlistener:this){//considero un NumberListener
			listenerClasses=getAllNumberListenerInterfaces(numberlistener.getClass());//ricavo tutti i NumberListener che implementa
			for (Class<? extends NumberListener<?>> numberlistenerextension:listenerClasses){//considero una classe che rappresenta un estensione del NumberListener
				this.executeAnnotatedMethods(numberlistenerextension, numberlistener, event);
			}
		}
	}
	
	private void executeAnnotatedMethods(Class<? extends NumberListener<?>> numberlistener,NumberListener<NUMBER> currentlistener,NumberEvent<NUMBER> event) {
		Method[] methods=numberlistener.getMethods();
		Range range=null;
		for (Method method:methods){
			try{
				if (method.isAnnotationPresent(Range.class)){
					range=method.getAnnotation(Range.class);
					if (MathAssister.extremis(
							event.getActualvalue().doubleValue(),
							range.inf(),
							range.sup(),
							range.infIncluded(),
							range.supIncluded())){
						//System.out.println(currentlistener.getClass().getSimpleName()+" "+method.toString());
						method.invoke(currentlistener,event);
					}
				}
			}catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException error){
				System.err.println("the "+currentlistener.getClass().getSimpleName()+" has failed doing the method \""+method.getName()+"\"");
				error.printStackTrace();
				System.exit(0);
			}
		}
	}
	
	
	//IMPLEMENTAZIONE DEI PUNTI 2 E 3
	
	private static HashSet<Class<? extends NumberListener<?>>> getAllNumberListenerInterfaces(Class<?> thisclass){
		HashSet<Class<? extends NumberListener<?>>> result=new HashSet<Class<? extends NumberListener<?>>>();
		Vector<Class<?>> allinterfaces=ClassAssister.getAllInterfaces(thisclass);
		for (int i=0;i<allinterfaces.size();i++){
			if (ClassAssister.isSuperInterface(NumberListener.class,allinterfaces.get(i))){
				result.add((Class<? extends NumberListener<?>>) allinterfaces.get(i));
			}
		}
		return result;
	}
}
